#pragma once
#include <list>
#include <map>
#include "TesInclude.h"
#include "TesToken.h"
#include "TesLexLocation.h"
#include "TesConfig.h"


class TES_EXPORT TesScanner
{
public:
	TesScanner( const TesConfig & config );
	~TesScanner();

	void								ScanFile( const tstring & filename );
	void								ScanString( const tstring & str );
	const list<TesToken> &				GetTokens() const									{ return mTokens; }

private:

	enum ScanState
	{
		SS_Normal,
		SS_InSingleQuoteString,
		SS_InDoubleQuoteString,
		SS_InSingleQuoteEscapeSequence,
		SS_InDoubleQuoteEscapeSequence,
		SS_InIdentifier,
		SS_InDecimal,
		SS_InOctal,
		SS_InHexadecimal,
		SS_InDouble,
		SS_InLineComment,
		SS_InExponent,

		SS_EnterDouble,
		SS_EnterScientific,
		SS_EnterExponent,
		SS_OneZeroPassed,
		SS_OneEqualPassed,							// =
		SS_OneUnequalPassed,						// ~
		SS_OneLessPassed,							// <
		SS_OneGreaterPassed,						// >
		SS_OneDotPassed,							// .
		SS_TwoDotPassed,							// ..
		SS_OneEscapeDigitPassedInSingle,			// \X
		SS_TwoEscapeDigitPassedInSingle,			// \XX
		SS_OneEscapeDigitPassedInDouble,			// \X
		SS_TwoEscapeDigitPassedInDouble,			// \XX

		SS_MAXCOUNT,
		SS_InvalidState
	};

	enum ScanCharType
	{
		SCT_Null,
		SCT_LineEnder,
		SCT_AlphaOrUnderscore,
		SCT_Digit,
		SCT_TabOrSpace,

		SCT_OpenParenthese,			// (
		SCT_CloseParenthese,		// )
		SCT_OpenBracket,			// [
		SCT_CloseBracket,			// ]
		SCT_OpenBrace,				// {
		SCT_CloseBrace,				// }

		SCT_Add,					// +
		SCT_Minus,					// -
		SCT_Star,					// *
		SCT_Slash,					// /
		SCT_Backslash,				// '\'
		SCT_Power,					// ^
		SCT_Percent,				// %
		SCT_Dot,					// .
		SCT_Less,					// <
		SCT_Greater,				// >
		SCT_Equal,					// =
		SCT_Unequal,				// !
		SCT_Sharp,					// #
		SCT_Colon,					// :
		SCT_Semicolon,				// ;
		SCT_SingleQuote,			// '
		SCT_DoubleQuote,			// "
		SCT_Comma,					// ,
		
		SCT_Other,
		SCT_MAXCOUNT
	};

	typedef ScanState (TesScanner::*ScanProcessor)( tchar ch );

	void								Scan( tistream & program );
	static ScanCharType					GetScanCharType( tchar ch );
	void								AddToken( const TesToken & token );
	void								AppendCharToCurrentString( tchar ch );
	void								ClearCurrentString();
	TesLexLocation						GetCurrentCharLexLocation() const;
	TesLexLocation						GetStringBeginLexLocation() const;
	void								AddIdentifierOrKeyword();

	list<TesToken>						mTokens;
	ScanProcessor						mProcessors[SS_MAXCOUNT];
	int									mStringBeginLine;
	int									mStringBeginColumn;
	int									mCurrentCharLine;
	int									mCurrentCharColumn;
	tstring								mCurrentString;
	tstring								mCurrentEscapeString;
	map<tstring, TesTokenType>			mKeywordMap;
	const TesConfig &					mConfig;
	tstring								mFilename;

private:

	ScanState							ProcessState_Normal( tchar ch );
	ScanState							ProcessState_InSingleQuoteString( tchar ch );
	ScanState							ProcessState_InDoubleQuoteString( tchar ch );
	ScanState							ProcessState_InSingleQuoteEscapeSequence( tchar ch );
	ScanState							ProcessState_InDoubleQuoteEscapeSequence( tchar ch );
	ScanState							ProcessState_InDecimal( tchar ch );
	ScanState							ProcessState_InOctal( tchar ch );
	ScanState							ProcessState_InHexadecimal( tchar ch );
	ScanState							ProcessState_InDouble( tchar ch );
	ScanState							ProcessState_InIdentifier( tchar ch );
	ScanState							ProcessState_InExponent( tchar ch );
	ScanState							ProcessState_InLineComment( tchar ch );

	ScanState							ProcessState_EnterDouble( tchar ch );
	ScanState							ProcessState_EnterScientific( tchar ch );
	ScanState							ProcessState_EnterExponent( tchar ch );
	ScanState							ProcessState_OneZeroPassed( tchar ch );
	ScanState							ProcessState_OneEqualPassed( tchar ch );
	ScanState							ProcessState_OneUnequalPassed( tchar ch );
	ScanState							ProcessState_OneLessPassed( tchar ch );
	ScanState							ProcessState_OneGreaterPassed( tchar ch );
	ScanState							ProcessState_OneDotPassed( tchar ch );
	ScanState							ProcessState_TwoDotPassed( tchar ch );
	ScanState							ProcessState_OneEscapeDigitPassedInSingle( tchar ch );
	ScanState							ProcessState_OneEscapeDigitPassedInDouble( tchar ch );
	ScanState							ProcessState_TwoEscapeDigitPassedInSingle( tchar ch );
	ScanState							ProcessState_TwoEscapeDigitPassedInDouble( tchar ch );
};
